package com.vote.services.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.collections.MultiMap;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import com.vote.dao.VoteOptionDAO;
import com.vote.dao.VoteQuestionDAO;
import com.vote.dao.VoteQuestionnaireDAO;
import com.vote.dao.VoteUserDAO;
import com.vote.domain.VoteOption;
import com.vote.domain.VoteQuestion;
import com.vote.domain.VoteQuestionnaire;
import com.vote.domain.VoteUser;
import com.vote.model.Option;
import com.vote.model.OptionSelectedForm;
import com.vote.model.Question;
import com.vote.model.Questionnaire;
import com.vote.services.QuestionnaireService;
import com.vote.utils.ModelTransform;


public class QuestionnaireServiceImpl implements QuestionnaireService {

    /**
     * Logger for this class
     */
    private static final Logger logger = Logger.getLogger(QuestionnaireServiceImpl.class);

    @Autowired
    VoteQuestionnaireDAO vqnDAO;
    
    @Autowired
    VoteUserDAO vuDAO;
    
    @Autowired
    VoteQuestionDAO vqDAO;
    
    @Autowired
    VoteOptionDAO voDAO;
    
    @Override
    public int insertQuestionnaire(Questionnaire questionnaire) throws Exception{
        VoteQuestionnaire vqn = ModelTransform.model2domain(questionnaire);
        int qnid = -1;
        int qid = -1;
        try{
            qnid = synInsertQuestionnaire(vqn);
        }
        catch(Exception e){
            logger.info("insert questionnaire "+vqn.getQuestionnaireName()+" fail!\n", e);
        }
        if(questionnaire.getQuestionList() == null){
//            logger.info("save the questionnaire("+questionnaire.getQuestionnaireName()+") but questionList is null");
//            throw new Exception("save the questionnaire("+questionnaire.getQuestionnaireName()+") but questionList is null");
            return qnid;
        }
        for(Question question : questionnaire.getQuestionList()){
            VoteQuestion vq = ModelTransform.model2domain(question);
            vq.setQuestionnaireId(qnid);
            try{
                qid = synInsertQuestion(vq);
            }
            catch(Exception e){
                logger.info("insert question "+vqn.getQuestionnaireName()+"->"+vq.getQuestionTitle()+" fail!\n", e);
                throw e;
            }
            if(question.getOptionList() == null){
                logger.info("save the question("+question.getQuestionTitle()+") but optionList is null");
                throw new Exception("save the question("+question.getQuestionTitle()+") but optionList is null");
            }
            for(Option option : question.getOptionList()){
                VoteOption vo = ModelTransform.model2domain(option);
                vo.setQuestionId(qid);
                try{
                    voDAO.insertOption(vo);
                }
                catch(Exception e){
                    logger.info("insert option "+vqn.getQuestionnaireName()+"->"+vq.getQuestionTitle()+"->"+vo.getOptionText()+" fail!\n", e);
                    throw e;
                }
            }
        }
        return qnid;
    }

    @Override
    public int deleteQuestionnaireById(int id) {
        Questionnaire qn = getQuestionnaireById(id);
        try{
//            for(Question q : qn.getQuestionList()){
//                for(Option o : q.getOptionList()){
//                    voDAO.deleteOption(o.getOptionId());
//                }
//                vqDAO.deleteQuestionById(q.getQuestionId());
//            }
//            vqnDAO.deleteQuestionnaireById(qn.getQuestionnaireId());
            vqnDAO.updateQuestionnaireStatus(id, Questionnaire.QuestionnaireStatus_Delete);
        }
        catch(Exception e){
            logger.info("delete questionnaire "+qn.getQuestionnaireName()+" fail!\n", e);
        }
        return 0;
    }

    @Override
    public List<Questionnaire> getHotQuestionnaireList(int offset, int length) {
        List<VoteQuestionnaire> voteQuestionnaireList = null;
        List<Questionnaire> questionnaireList = new ArrayList<Questionnaire>();
        try{
            voteQuestionnaireList = vqnDAO.getHotOnLineQuestionnaire(offset, length);
            if(voteQuestionnaireList != null){
                Questionnaire questionnaire = null;
                for(VoteQuestionnaire vq: voteQuestionnaireList){
                    questionnaire = ModelTransform.domain2model(vq);
                    questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
                    questionnaireList.add(questionnaire);
                }
            }
            else{
                logger.debug("get null hot questionnaire list");
            }
        }
        catch(Exception e){
            logger.info("get hot questionnaire list fail!\n", e);
            return null;
        }
        return questionnaireList;
    }

    @Override
    public int getHotQuestionnaireListCount() {
        int count = -1;
        try{
            count = vqnDAO.getHotOnlineQuestionnaireCount();
        }
        catch(Exception e){
            logger.debug("get hot online questionnaire count fail!\n", e);
            return -1;
        }
        return count;
    }

    @Override
    public List<Questionnaire> getNewQuestionnaireList(int offset, int length) {
        List<VoteQuestionnaire> voteQuestionnaireList = null;
        List<Questionnaire> questionnaireList = new ArrayList<Questionnaire>();
        try{
            voteQuestionnaireList = vqnDAO.getLatestOnlineQuestionnaire(offset, length);
            if(voteQuestionnaireList != null){
                Questionnaire questionnaire = null;
                for(VoteQuestionnaire vq: voteQuestionnaireList){
                    questionnaire = ModelTransform.domain2model(vq);
                    questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
                    questionnaireList.add(questionnaire);
                }
            }
            else{
                logger.debug("get null new questionnaire list");
            }
        }
        catch(Exception e){
            logger.info("get new questionnaire list fail!\n", e);
            return null;
        }
        return questionnaireList;
    }

    @Override
    public int getNewQuestionnaireListCount() {
        int count = -1;
        try{
            count = vqnDAO.getLatestOnlineQuestionnaireCount();
        }
        catch(Exception e){
            logger.info("get latest online questionnaire count fail!\n", e);
            return -1;
        }
        return count;
    }

    @Override
    public Questionnaire getQuestionnaireById(int id) {
        VoteQuestionnaire vq = null;
        Questionnaire questionnaire = null;
        try{
            vq = vqnDAO.getQuestionnaireById(id);
            if(vq == null){
                logger.debug("get null questionnaire by id = " + id);
                return null;
            }
            questionnaire = ModelTransform.domain2model(vq);
            questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
            questionnaire.setQuestionList(getQuestionList(id));
        }
        catch (Exception e){
            logger.info("get questionnaire fail!\n", e);
            return null;
        }
        return questionnaire;
    }

    @Override
    public List<Questionnaire> getQuestionnaireListByGroup(int group, int offset, int length) {
        List<VoteQuestionnaire> voteQuestionnaireList = null;
        List<Questionnaire> questionnaireList = new ArrayList<Questionnaire>();
        try{
            voteQuestionnaireList = vqnDAO.getQuestionnaireListByGroup(group, offset, length);
            if(voteQuestionnaireList != null){
                Questionnaire questionnaire = null;
                for(VoteQuestionnaire vq: voteQuestionnaireList){
                    questionnaire = ModelTransform.domain2model(vq);
                    questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
                    questionnaireList.add(questionnaire);
                }
            }
            else{
                logger.debug("get null questionnaire list by group when group = "+ group);
            }
        }
        catch(Exception e){
            logger.info("get questionnaire list by group fail!\n", e);
            return null;
        }
        return questionnaireList;
    }

    @Override
    public List<Questionnaire> getQuestionnaireListByType(int type, int offset, int length) {
        List<VoteQuestionnaire> voteQuestionnaireList = null;
        List<Questionnaire> questionnaireList = new ArrayList<Questionnaire>();
        try{
            voteQuestionnaireList = vqnDAO.getQuestionnaireListByType(type, offset, length);
            if(voteQuestionnaireList != null){
                Questionnaire questionnaire = null;
                for(VoteQuestionnaire vq: voteQuestionnaireList){
                    questionnaire = ModelTransform.domain2model(vq);
                    questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
                    questionnaireList.add(questionnaire);
                }
            }
            else{
                logger.debug("get null questionnaire list by type when type = " + type);
            }
        }
        catch(Exception e){
            logger.info("get questionnaire list by type fail!\n", e);
            return null;
        }
        return questionnaireList;
    }

    @Override
    public int getQuestionnaireListCountByGroup(int group) {
        int count = -1;
        try{
            count = vqnDAO.getQuestionnaireCountByGroup(group);
        }
        catch(Exception e){
            logger.info("get count of questionnaire list by group fail!\n", e);
            return -1;
        }
        return count;
    }

    @Override
    public int getQuestionnaireListCountByType(int type) {
        int count = -1;
        try{
            count = vqnDAO.getQusetionnaireCountByType(type);
        }
        catch(Exception e){
            logger.info("get count of questionnaire list by type fail!\n", e);
            return -1;
        }
        return count;
    }

    @Override
    public List<Questionnaire> getUserQuestionnaireListByUserId(int userId, int offset, int length) {
        List<VoteQuestionnaire> voteQuestionnaireList = null;
        List<Questionnaire> questionnaireList = new ArrayList<Questionnaire>();
        try{
            voteQuestionnaireList = vqnDAO.getQuestionnaireListByUserId(userId, offset, length);
            if(voteQuestionnaireList != null){
                Questionnaire questionnaire = null;
                for(VoteQuestionnaire vq: voteQuestionnaireList){
                    questionnaire = ModelTransform.domain2model(vq);
                    questionnaire.setOwnerName(getUserNameByUserId(vq.getUserId()));
                    questionnaireList.add(questionnaire);
                }
            }
            else{
                logger.debug("get null user questionnaire list by user id = " + userId);
            }
        }
        catch(Exception e){
            logger.info("get questionnaire list by user id fail!\n", e);
            return null;
        }
        return questionnaireList;
    }

    @Override
    public int getUserQuestionnaireListCountByUserId(int userId) {
        int count = -1;
        try{
            count = vqnDAO.getQuestionnaireCountByUserId(userId);
        }
        catch(Exception e){
            logger.info("get count of questionnaire list by userId fail!\n", e);
            return -1;
        }
        return count;
    }

    @Override
    public int offlineQuestionnaireById(int id) {
        vqnDAO.updateQuestionnaireStatus(id, Questionnaire.QuestionnaireStatus_Offline);
        return 0;
    }

    @Override
    public int onlineQuestionnaireById(int id) {
        vqnDAO.updateQuestionnaireStatus(id, Questionnaire.QuestionnaireStatus_Online);
        return 0;
    }

    @Override
    public int insertQuestionnaireForm(OptionSelectedForm osf) {
        try{
        vqnDAO.addCount(osf.getQuestionnaireId());
        MultiMap map = osf.getSelectedMap();
        Iterator<MultiMap.Entry<Integer, Collection<Integer>>> iter = map.entrySet().iterator();
        while(iter.hasNext()){
            MultiMap.Entry<Integer, Collection<Integer>> entry = iter.next();
            vqDAO.addCount(entry.getKey());
            for(Integer i : entry.getValue()){
                voDAO.addCount(i);
            }
        }
        }
        catch(Exception e){
            logger.info("submit questionnaire form fail!\n", e);
        }
        return 0;
    }

    private List<Question> getQuestionList(int questionnaireId){
        List<VoteQuestion> voteQuestionList = null;
        List<Question> questionList = new ArrayList<Question>();
        
        try{
            voteQuestionList = vqDAO.getQuestionListByQuestionnaireId(questionnaireId);
            if(voteQuestionList != null){
                Question question = null;
                for(VoteQuestion vq : voteQuestionList){
                    question = ModelTransform.domain2model(vq);
                    question.setOptionList(getOptionList(vq.getQuestionId()));
                    questionList.add(question);
                }
            }
            else{
                logger.debug("get null question list by questionnaireId = " + questionnaireId);
            }
        }
        catch (Exception e){
            logger.info("get question list fail!\n", e);
            return null;
        }
        return questionList;
    }
    
    private List<Option> getOptionList(int questionId){
        List<VoteOption> voteOptionList = null;
        List<Option> optionList = new ArrayList<Option>();
        
        try{
            voteOptionList = voDAO.getOptionListByQuestionId(questionId);
            if(voteOptionList != null){
                Option option = null;
                for(VoteOption vo : voteOptionList){
                    option = ModelTransform.domain2mode(vo);
                    optionList.add(option);
                }
            }
            else{
                logger.debug("get null option list by questionId = " + questionId);
            }
        }
        catch (Exception e){
            logger.info("get option list fail!\n", e);
            return null;
        }
        return optionList;
    }
    
    private String getUserNameByUserId(int id){
        VoteUser voteUser = null;
        try{
            voteUser = vuDAO.getUser(id);
        }
        catch(Exception e){
            logger.info("get user name by user id in QuestionnaireServiceImpl fail!\n", e);
            return null;
        }
        return voteUser.getUserName();
    }
    
    private synchronized int synInsertQuestionnaire(VoteQuestionnaire vqn){
        int id = -1;
        vqnDAO.insertQuestionnaire(vqn);
        id = vqnDAO.getLastInsertId();
        return id;
    }
    
    private synchronized int synInsertQuestion(VoteQuestion vq){
        int id = -1;
        vqDAO.insertQuestion(vq);
        id = vqDAO.getLastInsertId();
        return id;
    }
}
